/*
 * Albareth - an action roleplaying game.
 * Copyright (C) 2008 Jens Anuth
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 *   02110-1301, USA.
 * 
 * $Id: BasicItemContainer.java 48 2008-05-17 02:04:48Z jens464 $
*/
package albareth.core.entity.item;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import frosch.util.Log;

import albareth.core.GameEffect;
import albareth.core.entity.Entity;
import albareth.core.entity.Item;
import albareth.core.entity.ItemContainer;
import albareth.core.entity.ItemContainerChangeListener;
import albareth.core.entity.Mobile;
import albareth.core.entity.PlayerCharacter;
import albareth.frontend.Frontend;
import albareth.frontend.Resources;
import albareth.frontend.Tile;

public class BasicItemContainer extends Item implements ItemContainer
{
    private int _capacity = 8;
    
    private ArrayList _inventory = new ArrayList();
    
    //private ItemContainerChangeListener _containerListener = null;
    private List _containerListeners = null;

    
    public BasicItemContainer(String name, Tile tile)
    {
        super(name, tile);
    }
    
    public Object clone() throws CloneNotSupportedException
    {
        throw new CloneNotSupportedException("Cannot clone containers yet.");
    }

    
    public void addItemContainerChangeListener(
            ItemContainerChangeListener listener)
    {
        if (_containerListeners == null) {
            _containerListeners = new LinkedList();
        } else if (_containerListeners.contains(listener)) {
            return;
        }
        _containerListeners.add(listener);
    }
    
    private void notifyChangeListeners()
    {
        if (_containerListeners == null) {
            return;
        }
        for (Iterator it = _containerListeners.iterator(); it.hasNext(); )
        {
            ItemContainerChangeListener listener =
                (ItemContainerChangeListener)it.next();
            listener.itemContainerChanged(this);
        }
    }
    
    public boolean dropItem(Item item)
    {
        if (removeItem(item)) {
            item.moveTo(getLocation());
            return true;
        }
        return false;
    }

    public Item dropItem(Item item, int amount)
    {
        if (!containsItem(item)) {
            return null;
        }
        
        if (amount < item.getAmount()) {
            try {
                Item clone = (Item)item.clone();
                clone.setAmount(amount);
                //clone.setOwner(null);
                clone.moveTo(getLocation());
                item.consume(amount);
                return clone;
            } catch (CloneNotSupportedException e) {
                Log.error(
                        "Could not clone item " + item.getName() +
                        " for drop: " + e
                ); 
                return null;
            }
        } else {
            if (dropItem(item)) {
                return item;
            } else {
                return null;
            }
        }
    }

    public Item dropItem(int i)
    {
        Item item = removeItem(i);
        if (item != null) {
            item.moveTo(getLocation());
        }
        return item;
    }
    
    public void dropAllItems()
    {
        for (Iterator it = _inventory.iterator(); it.hasNext(); )
        {
            Item item = (Item)it.next();
            item.setOwner(null);
            item.moveTo(getLocation());
            it.remove();
            notifyChangeListeners();
        }
    }

    public List getAllItems()
    {
        return _inventory;
    }

    public boolean addItem(Item item)
    {
        boolean success = addItemImpl(item);
        if (success) {
            notifyChangeListeners();
        }
        return success;
    }
    
    private boolean addItemImpl(Item item)
    {
        if (tryStack(item)) {
            return true;
        }
        if (numItems() >= getCapacity()) {
            return false;
        }
        
        boolean success = _inventory.add(item);
        if (success) {
            if (item.isInGame()) {
                item.remove();
            }
            item.setOwner(this);
        }
        
        
        
        return success;

    }
    
    /**
     * Try to stack an item onto an already existing one.
     */
    private boolean tryStack(Item newItem)
    {
        for (Iterator it = _inventory.iterator(); it.hasNext(); )
        {
            Item myItem = (Item)it.next();
            if (myItem.isStackable() && myItem.isStackableWith(newItem)) {
                myItem.setAmount(myItem.getAmount() + newItem.getAmount());
                newItem.remove();
                return true;
            }
        }
        return false;
    }

    public boolean addAllItems(List items)
    {
        for (Iterator it = items.iterator(); it.hasNext(); )
        {
            Item item = (Item)it.next();
            addItemImpl(item);
        }
        notifyChangeListeners();
        return true;
    }

    
    public void removeAllItems()
    {
        for (Iterator it = _inventory.iterator(); it.hasNext(); )
        {
            Item item = (Item)it.next();
            item.setOwner(null);
            it.remove();
        }
        notifyChangeListeners();
    }
    
    public Item removeItem(int index)
    {
        Item item = (Item)_inventory.get(index);
        if (removeItem(item)) {
            return item;
        }
        return null;
    }
    
    public boolean removeItem(Item item)
    {
        boolean success = _inventory.remove(item);
        if (success)
        {
            if (item.getOwner() == this) { //??
                item.setOwner(null);
            }
            notifyChangeListeners();
        }
        return success; 
    }

    public boolean containsItem(Item item)
    {
        return _inventory.contains(item);
    }
    
    public int numItems()
    {
        return _inventory.size();
    }
    
    protected boolean onDestroy(Entity causer, int damageType)
    {
        emitEffect(
                GameEffect.stationary(
                        Resources.EFFECT_DEBRIS, getLocation(), 1000
                )
        );
        emitSound(Resources.SOUND_CONTAINER_BREAK);
        
        dropAllItems();

        return true;
    }

    protected boolean onActivate(Mobile src)
    {
        if (src.isPlayerControlled()) {
            Frontend frontend = ((PlayerCharacter)src).getFrontend();
            addItemContainerChangeListener(frontend);
            //src.eventMsg("You open the " + getName() + ".");
            frontend.displayContainer(this);
            src.emitSound(Resources.SOUND_OPEN_CHEST);
        }
        return true;
    }

    public int getCapacity()
    {
        return _capacity;
    }

    public void setCapacity(int capacity)
    {
        _capacity = capacity;
    }

    public void enchant(int level)
    {
    }

}
